﻿/// @file khash.c
#include "stdafx.h"
#include "sbcs.h"

//////////////////////////////////////////////////////////////////////////
// 해시

/// 포인터 해시. 일반적인 해시를 의미함.
/// @date 2013-12-22
/// @param p 포인터
/// @return 해시값
ksize_t k_ptrhash(kpointer p)
{
	ldiv_t t = ldiv((long)(kint)(ksize_t)p, 127773);
	t.rem = 16807 * t.rem - 2836 * t.quot;

	if (t.rem < 0)
		t.rem += K_MAX_INT;

	return (ksize_t)t.rem;
}

/// 시간 해시. 현재 시각을 이용하여 해시값을 만든다.
/// @date 2013-12-22
/// @return 해시값.
ksize_t k_timedhash(void)
{
	static kuint dif = 0;

	time_t t = time(NULL);
	clock_t c = clock();

	ksize_t h1, h2;
	ksize_t i;
	ksbyte* p;

	h1 = 0;
	p = (ksbyte*)&t;

	for (i = 0; i < sizeof(time_t); i++)
	{
		h1 *= K_MAX_BYTE + 2;
		h1 += p[i];
	}

	h2 = 0;
	p = (ksbyte*)&c;

	for (i = 0; i < sizeof(clock_t); i++)
	{
		h2 *= K_MAX_BYTE + 2;
		h2 += p[i];
	}

	return (h1 + dif++) ^ h2;
}

/// 콜백 해시. 함수 콜백을 해시값으로 만들어 준다.
/// @date 2013-12-22
/// @param prime8 8비트 짜리 고유 숫자.
/// @param func   함수.
/// @param data   데이터.
/// @return 해시값.
ksize_t k_cbhash(kint prime8, kfunc func, kpointer data)
{
	ksize_t h;
	kany v;

	v.func = func;

#if _SB_64_
	// PP FF FF FF FD DD DD DD
	h = K_CONST_ULONG(prime8 & 0xFF) << K_CONST_ULONG(56);
	h |= (k_ptrhash(v.p) & 0xFFFFFFF) << 28;
	h |= k_ptrhash(data) & 0xFFFFFFF;
#else
	// PP FF FD DD
	h = (prime8 & 0xFF) << 24;
	h |= (k_ptrhash(v.p) & 0xFFF) << 12;
	h |= k_ptrhash(data) & 0xFFF;
#endif

	return h;
}

/// 가까운 소수 얻기. 처리할 수 있는 최소 소수는 11, 최대 소수는 13845163.
/// @date 2013-12-22
/// @param value 값.
/// @return 만들어진 소수.
ksize_t k_primeclose(ksize_t value)
{
	static const ksize_t s_prime_table[] =
	{
		11, 19, 37, 73, 109, 163, 251, 367, 557, 823, 1237, 1861, 2777, 4177, 6247,
		9371, 14057, 21089, 31627, 47431, 71143, 106721, 160073, 240101, 360163, 540217,
		810343, 1215497, 1823231, 2734867, 4102283, 6153409, 9230113, 13845163,
	};
	ksize_t i;

	for (i = 0; i < K_COUNTOF(s_prime_table); i++)
		if (s_prime_table[i] > value)
			return s_prime_table[i];

	return s_prime_table[i - 1];
}

/// 제곱 소수 얻기. 근거리에 해당하는 제곱 소수를 계산해준ㄷ
/// @date 2013-12-22
/// @param value		  값.
/// @param min			  최소.
/// @param [in,out] shift 이 값이 널이 아니면 다음 값이 들어간다: 쉬프트.
/// @return 새로운 소수.
ksize_t k_primeshift(ksize_t value, ksize_t min, ksize_t* shift)
{
	static const ksize_t s_prime_shift_table[] =
	{
		/* 1<<0 */
		1, 2, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749,
		/* 1<<16 */
		65521, 131071, 262139, 524287, 1048573, 2097143, 4194301, 8388593,
		16777213, 33554393, 67108859, 134217689, 268435399, 536870909, 1073741789,
		/* 1<<31 */
		2147483647
	};
	ksize_t ts;

	for (ts = 0; value; ts++)
		value >>= 1;

	ts = K_MAX(min, ts);

	if (shift) *shift = ts;

	return s_prime_shift_table[ts];
}
